package org.itboys.pay.union;

import org.apache.commons.lang.StringUtils;
import org.itboys.pay.tools.NumberCalculateUtils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Map.Entry;

public class Unionpay {
	private static String encoding = "UTF-8";
	/**
	 * 5.0.0
	 */
	private static String version = "5.0.0";

	/**
	 * http://localhost:8080/ACPTest/acp_front_url.do
	 */
	// 后台服务对应的写法参照 FrontRcvResponse.java
	private static String frontUrl = "http://localhost:8080/ACPTest/acp_front_url.do";

	/**
	 * java main方法 数据提交 　　 对数据进行签名
	 * 
	 * @param contentData
	 * @return　签名后的map对象
	 */
	@SuppressWarnings("unchecked")
	private static Map<String, String> signData(Map<String, ?> contentData) {
		Entry<String, String> obj = null;
		Map<String, String> submitFromData = new HashMap<String, String>();
		for (Iterator<?> it = contentData.entrySet().iterator(); it.hasNext();) {
			obj = (Entry<String, String>) it.next();
			String value = obj.getValue();
			if (StringUtils.isNotBlank(value)) {
				// 对value值进行去除前后空处理
				submitFromData.put(obj.getKey(), value.trim());
				// System.out
				// .println(obj.getKey() + "-->" + String.valueOf(value));
			}
		}
		/**
		 * 签名
		 */
		SDKUtil.sign(submitFromData, encoding);

		return submitFromData;
	}

	/**
	 * java main方法 数据提交 提交到后台
	 * 
	 * @return 返回报文 map
	 */
	private static Map<String, String> submitUrl(
			Map<String, String> submitFromData, String requestUrl) {
		String resultString = "";
		// System.out.println("requestUrl====" + requestUrl);
		// System.out.println("submitFromData====" + submitFromData.toString());
		/**
		 * 发送
		 */
		HttpClient hc = new HttpClient(requestUrl, 30000, 30000);
		try {
			int status = hc.send(submitFromData, encoding);
			if (200 == status) {
				resultString = hc.getResult();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		Map<String, String> resData = new HashMap<String, String>();
		/**
		 * 验证签名
		 */
		if (null != resultString && !"".equals(resultString)) {
			// 将返回结果转换为map
			resData = SDKUtil.convertResultStringToMap(resultString);
			// if (SDKUtil.validate(resData, encoding)) {
			// System.out.println("验证签名成功");
			// } else {
			// System.out.println("验证签名失败");
			// }
			// // 打印返回报文
			// System.out.println("打印返回报文：" + resultString);
		}
		return resData;
	}

	/**
	 * APP支付调用的方法
	 * @param orderNo  订单编号
	 * @param orderAmount  支付金额
	 * @param callBackUrl  回调地址
	 * @param merId  商户号
	 * @return
	 */
	public static String gettn(String orderNo, Double orderAmount,
			String callBackUrl, String merId) {
		/**
		 * 参数初始化 在java main 方式运行时必须每次都执行加载 如果是在web应用开发里,这个方写在可使用监听的方式写入缓存,无须在这出现
		 */
		SDKConfig.getConfig().loadPropertiesFromSrc();// 从classpath加载acp_sdk.properties文件
		/**
		 * 组装请求报文
		 */
		Map<String, String> data = new HashMap<String, String>();
		// 版本号
		data.put("version", "5.0.0");
		// 字符集编码 默认"UTF-8"
		data.put("encoding", "UTF-8");
		// 签名方法 01 RSA
		data.put("signMethod", "01");
		// 交易类型 01-消费
		data.put("txnType", "01");
		// 交易子类型 01:自助消费 02:订购 03:分期付款
		data.put("txnSubType", "01");
		// 业务类型
		data.put("bizType", "000201");
		// 渠道类型，07-PC，08-手机
		data.put("channelType", "08");
		// 前台通知地址 ，控件接入方式无作用
		data.put("frontUrl", "123");
		// 后台通知地址
		data.put("backUrl", callBackUrl);
		// 接入类型，商户接入填0 0- 商户 ， 1： 收单， 2：平台商户
		data.put("accessType", "0");
		// 商户号码，请改成自己的商户号
		data.put("merId", merId);
		// 商户订单号，8-40位数字字母
		data.put("orderId", orderNo);
		// 订单发送时间，取系统时间
		data.put("txnTime",
				new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()));
		// 交易金额，单位分
		// data.put("txnAmt", "1");//测试金额
		data.put("txnAmt", NumberCalculateUtils.multiply(100, orderAmount)
				.toString());
		// 交易币种
		data.put("currencyCode", "156");
		// 请求方保留域，透传字段，查询、通知、对账文件中均会原样出现
		// data.put("reqReserved", "透传信息");
		// 订单描述，可不上送，上送时控件中会显示该信息
		data.put("orderDesc", "钓客订单");

		data = Unionpay.signData(data);

		// 交易请求url 从配置文件读取
		String requestAppUrl = SDKConfig.getConfig().getAppRequestUrl();
		Map<String, String> resmap = Unionpay.submitUrl(data, requestAppUrl);
		return resmap.get("tn");
	}

	/**
	 * 银联支付异步回调解析参数  返回空说明校验失败
	 * @param req
	 * @return
	 * @throws ServletException
	 * @throws IOException
	 */
	public static Map<String, String> getValiData(HttpServletRequest req)
			throws ServletException, IOException {

		LogUtil.writeLog("BackRcvResponse接收后台通知开始");

		req.setCharacterEncoding("ISO-8859-1");
		String encoding = req.getParameter(SDKConstants.param_encoding);
		// 获取银联通知服务器发送的后台通知参数
		Map<String, String> reqParam = getAllRequestParam(req);

		LogUtil.printRequestLog(reqParam);

		Map<String, String> valideData = null;
		if (null != reqParam && !reqParam.isEmpty()) {
			Iterator<Entry<String, String>> it = reqParam.entrySet().iterator();
			valideData = new HashMap<String, String>(reqParam.size());
			while (it.hasNext()) {
				Entry<String, String> e = it.next();
				String key = (String) e.getKey();
				String value = (String) e.getValue();
				value = new String(value.getBytes("ISO-8859-1"), encoding);
				valideData.put(key, value);
			}
		}

		// 重要！验证签名前不要修改reqParam中的键值对的内容，否则会验签不过
		if (!AcpService.validate(valideData, encoding)) {
			// LogUtil.writeLog("验证签名结果[失败].");
			// 验签失败，需解决验签问题
			return null;
		} else {
			// LogUtil.writeLog("验证签名结果[成功].");
			// 【注：为了安全验签成功才应该写商户的成功处理逻辑】交易成功，更新商户订单状态

			// String orderId =valideData.get("orderId");
			// //获取后台通知的数据，其他字段也可用类似方式获取
			// String respCode =valideData.get("respCode");
			// //获取应答码，收到后台通知了respCode的值一般是00，可以不需要根据这个应答码判断。
			return valideData;
		}
		// LogUtil.writeLog("BackRcvResponse接收后台通知结束");
		// 返回给银联服务器http 200 状态码
	}

	/**
	 * 获取请求参数中所有的信息
	 * 
	 * @param request
	 * @return
	 */
	private static Map<String, String> getAllRequestParam(
			final HttpServletRequest request) {
		Map<String, String> res = new HashMap<String, String>();
		Enumeration<?> temp = request.getParameterNames();
		if (null != temp) {
			while (temp.hasMoreElements()) {
				String en = (String) temp.nextElement();
				String value = request.getParameter(en);
				res.put(en, value);
				// 在报文上送时，如果字段的值为空，则不上送<下面的处理为在获取所有参数数据时，判断若值为空，则删除这个字段>
				// System.out.println("ServletUtil类247行  temp数据的键=="+en+"     值==="+value);
				if (null == res.get(en) || "".equals(res.get(en))) {
					res.remove(en);
				}
			}
		}
		return res;
	}
}
